package top.azusall.securitydemo.config;

import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler;
import org.springframework.security.access.expression.method.MethodSecurityExpressionHandler;
import org.springframework.security.access.hierarchicalroles.RoleHierarchy;
import org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
import top.azusall.model.pojo.Permission;
import top.azusall.model.pojo.Role;
import top.azusall.model.pojo.User;
import top.azusall.securitydemo.common.MyUserDetail;
import top.azusall.securitydemo.filter.JwtFilter;
import top.azusall.securitydemo.mapper.RolePermissionMapper;
import top.azusall.securitydemo.mapper.UserMapper;
import top.azusall.securitydemo.mapper.UserPermissionMapper;
import top.azusall.securitydemo.mapper.UserRoleMapper;
import top.azusall.securitydemo.thread.UserDetailThreadLocalUtil;

import java.util.ArrayList;
import java.util.List;

/**
 * @author houmo
 */
@Slf4j
@Configuration
@EnableWebSecurity
@EnableMethodSecurity
public class SecurityConfig {

    @Resource
    private UserMapper userMapper;
    @Resource
    private UserRoleMapper userRoleMapper;
    @Resource
    private UserPermissionMapper userPermissionMapper;
    @Resource
    private RolePermissionMapper rolePermissionMapper;

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
//                .httpBasic(Customizer.withDefaults())
//                .formLogin(Customizer.withDefaults())
                .authorizeHttpRequests(authorize -> authorize
                        .requestMatchers("/login").permitAll()
                        .anyRequest().authenticated()
                );


        http.addFilterAfter(new JwtFilter(), AnonymousAuthenticationFilter.class);

        return http.build();
    }

    @Bean
    public UserDetailsService userDetailsService() {
        return username -> {
            log.info("从数据库加载userDetail:{} ", username);
            User user = userMapper.selectOne(Wrappers.<User>lambdaQuery().eq(User::getUsername, username));
            if (user == null) {
                return null;
            }

            // 查询角色权限
            ArrayList<SimpleGrantedAuthority> grantedAuthorities = new ArrayList<>();
            List<Role> rolesByUserId = userRoleMapper.getRolesByUserId(user.getId());
            for (Role role : rolesByUserId) {
                grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_" + role.getName()));
                // 查询角色权限
                List<Permission> permissionsByRoleId = rolePermissionMapper.getPermissionsByRoleId(role.getId());
                for (Permission permission : permissionsByRoleId) {
                    grantedAuthorities.add(new SimpleGrantedAuthority(permission.getName()));
                }
            }
            // 查询用户特殊权限
            List<Permission> permissionByUserId = userPermissionMapper.getPermissionsByUserId(user.getId());
            for (Permission permission : permissionByUserId) {
                grantedAuthorities.add(new SimpleGrantedAuthority(permission.getName()));
            }
            log.info("成功从数据库加载userDetail:{}, grantedAuthorities: {}", username, JSON.toJSON(grantedAuthorities));





            MyUserDetail myUserDetail = new MyUserDetail();
            myUserDetail.setUser(user);
            myUserDetail.setAuthorities(grantedAuthorities);
            // 保存
            UserDetailThreadLocalUtil.set(myUserDetail);
            return myUserDetail;
        };
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder(12);
    }

    @Bean
    public AuthenticationManager authenticationManager(
            UserDetailsService userDetailsService,
            PasswordEncoder passwordEncoder) {
        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        authenticationProvider.setUserDetailsService(userDetailsService);
        authenticationProvider.setPasswordEncoder(passwordEncoder);

        ProviderManager providerManager = new ProviderManager(authenticationProvider);

        providerManager.setEraseCredentialsAfterAuthentication(true);

        return providerManager;
    }


    /**
     * 设置角色继承关系
     */
    @Bean
    static RoleHierarchy roleHierarchy() {
        return RoleHierarchyImpl.withDefaultRolePrefix()
                .role("ADMIN").implies("USER")
                .build();
    }

    // and, if using pre-post method security also add
    @Bean
    static MethodSecurityExpressionHandler methodSecurityExpressionHandler(RoleHierarchy roleHierarchy) {
        DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
        expressionHandler.setRoleHierarchy(roleHierarchy);
        return expressionHandler;
    }

}
